# -*- coding: utf-8 -*-
import numbers


class Field:
    pass


class IntField(Field):
    def __init__(self, db_column, min_value=None, max_value=None):
        self._value = None
        self.db_column = db_column

        if min_value is not None:
            if not isinstance(min_value, numbers.Integral):
                raise ValueError("min_value must be int")
            elif min_value < 0:
                raise ValueError('min_value must be a positive integer')
        if max_value is not None:
            if not isinstance(max_value, numbers.Integral):
                raise ValueError("max_value must be int")
            elif max_value < 0:
                raise ValueError('max_value must be a positive integer')
        if min_value is not None and max_value is not None:
            if min_value > max_value:
                raise ValueError('min_value must be less than max_value')
        self.min_value = min_value
        self.max_value = max_value

    def __get__(self, instance, owner):
        return self._value

    def __set__(self, instance, value):
        if not isinstance(value, int):
            raise ValueError('value must be an integer')
        if value < 0:
            raise ValueError('value must be a positive integer')
        if self.min_value is not None and value < self.min_value:
            raise ValueError('value must be greater than min_value')
        if self.max_value is not None and value > self.max_value:
            raise ValueError('value must be less than max_value')
        self._value = value


class CharField(Field):
    def __init__(self, db_column, max_length=None):
        self._value = None
        self.db_column = db_column
        if max_length is None:
            raise ValueError("you must specify max_length for char field")

        self.max_length = max_length

    def __get__(self, instance, owner):
        return self._value

    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise ValueError('value must be a string')
        if len(value) > self.max_length:
            raise ValueError('value must be less than max_length')
        self._value = value


class ModelMetaClass(type):
    def __new__(cls, name, bases, attrs, **kwargs):
        if name == "BaseModel":
            return super().__new__(cls, name, bases, attrs, **kwargs)
        fields = {}
        for key, value in attrs.items():
            if isinstance(value, Field):
                fields[key] = value
        attrs_meta = attrs.get("Meta", None)
        _meta = {}
        db_table = name.lower()
        if attrs_meta:
            table = getattr(attrs_meta, "db_table", None)
            if table is not None:
                db_table = table
        _meta['db_table'] = db_table
        attrs['_meta'] = _meta
        attrs['fields'] = fields

        del attrs["Meta"]

        return super().__new__(cls, name, bases, attrs, **kwargs)


class BaseModel(metaclass=ModelMetaClass):
    """
    TODO:
    """

    def __init__(self, *args, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)
        super().__init__()

    def save(self):
        fields = []
        values = []
        for key, value in self.fields.items():
            db_column = value.db_column
            if db_column is None:
                db_column = key.lower()
            fields.append(db_column)
            value = getattr(self, key)
            values.append(value)
        # sql = f"insert {db_table}({fields}) value({values})".format(db_table=self._meta["db_table"], fields=",".join(fields))
        pass


class User(BaseModel):
    name = CharField(db_column="name", max_length=10)
    age = IntField(db_column="age", min_value=0, max_value=100)

    class Meta:
        db_table = "user"


def orm_test():
    user = User()
    user.name = "jack"
    user.age = 100
    print(user.name)
    print(user.age)


def debug_test():
    for i in range(5):
        out2 = Fib(i + 1)
        print("包含{i}项的为{l}".format(i=i + 1, l=out2))


def Fib(n):
    l = []
    for i in range(n):
        l.append(fib_cal(i + 1))
    return l


def fib_cal(m):
    a, b = 0, 1
    for j in range(m):
        a, b = b, a + b
    return a


if __name__ == '__main__':
    # debug_test()
    orm_test()
